package com.geniusk.system.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.geniusk.common.core.JSONResult;
import com.geniusk.common.utils.DeviceUtil;
import com.geniusk.common.utils.PageUtil;
import com.geniusk.file.utils.MinioUtil;
import com.geniusk.mqtt.utils.MqttUtil;
import com.geniusk.security.annotation.PreFuncAuth;
import com.geniusk.security.utils.SecurityUtil;
import com.geniusk.system.model.bo.device.*;
import com.geniusk.system.model.pojo.Device;
import com.geniusk.system.service.DeviceService;
import com.geniusk.system.service.ModelPropertyService;
import com.geniusk.wss.core.TopicConstants;
import lombok.extern.slf4j.Slf4j;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 设备管理接口
 */
@Slf4j
@RestController
@RequestMapping("/system/device")
public class DeviceController {

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private ModelPropertyService modelPropertyService;

    @Autowired
    private DeviceUtil deviceUtil;

    @Autowired
    private MinioUtil minioUtil;

    /**
     * ID查询设备
     */
    @PostMapping("/selectDeviceById")
    @PreFuncAuth("SYS:DEVICE:SELECT")
    public JSONResult selectDeviceById(@Valid @RequestBody SelectDeviceByIdBO selectDeviceByIdBO) {
        Long deviceId = selectDeviceByIdBO.getDeviceId();
        Device device = deviceService.selectDeviceById(deviceId);
        String deviceSecret = DeviceUtil.encryptBase64(deviceId.toString(),device.getDeviceSecret());
        device.setDeviceSecret(deviceSecret);
        Map<String, Object> result = new HashMap<>();
        result.put("device", device);
        return JSONResult.ok(result);
    }

    /**
     * 分页查询设备
     */
    @PostMapping("/selectDeviceByPage")
    @PreFuncAuth("SYS:DEVICE:SELECT")
    public JSONResult selectDeviceByPage(@Valid @RequestBody SelectDeviceByPageBO selectDeviceByPageBO) {
        int pageNum = selectDeviceByPageBO.getPageNum();
        int pageSize = selectDeviceByPageBO.getPageSize();
        Device device = JSONUtil.parse(selectDeviceByPageBO).toBean(Device.class);
        device.setCreateBy(SecurityUtil.getUsername());
        PageUtil.startPage(pageNum, pageSize);
        List<Device> deviceList = deviceService.selectDeviceByPage(device);
        Map<String, Object> result = PageUtil.getResultTableData(deviceList);
        return JSONResult.ok(result);
    }

    /**
     * 添加设备
     */
    @PostMapping("/insertDevice")
    @PreFuncAuth("SYS:DEVICE:INSERT")
    public JSONResult insertDevice(@Valid @RequestBody InsertDeviceBO insertDeviceBO) {
        Device device = JSONUtil.parse(insertDeviceBO).toBean(Device.class);
        Long deviceId = IdUtil.getSnowflake().nextId();
        device.setDeviceId(deviceId);
        device.setDeviceSecret(DeviceUtil.getDeviceSecret());
        device.setCreateBy(SecurityUtil.getUsername());
        int rows = deviceService.insertDevice(device);
        Map<String, Object> result = new HashMap<>();
        result.put("rows", rows);
        return JSONResult.ok(result);
    }

    /**
     * 修改设备
     */
    @PostMapping("/updateDevice")
    @PreFuncAuth("SYS:DEVICE:UPDATE")
    public JSONResult updateDevice(@Valid @RequestBody UpdateDeviceBO updateDeviceBO) {
        Device device = JSONUtil.parse(updateDeviceBO).toBean(Device.class);
        device.setUpdateBy(SecurityUtil.getUsername());
        int rows = deviceService.updateDevice(device);
        Map<String, Object> result = new HashMap<>();
        result.put("rows", rows);
        return JSONResult.ok(result);
    }

    /**
     * 删除设备
     */
    @PostMapping("/deleteDeviceByIds")
    @PreFuncAuth("SYS:DEVICE:DELETE")
    public JSONResult deleteDeviceByIds(@Valid @RequestBody DeleteDeviceByIdsBO deleteDeviceByIdsBO) {
        int rows = deviceService.deleteDeviceByIds(deleteDeviceByIdsBO.getDeviceIds());
        Map<String, Object> result = new HashMap<>();
        result.put("rows", rows);
        return JSONResult.ok(result);
    }

    /**
     * 获取设备令牌
     */
    @PostMapping("/getAccessToken")
    @PreFuncAuth("SYS:DEVICE:TOKEN")
    public JSONResult getAccessToken(@Valid @RequestBody SelectDeviceByIdBO selectDeviceByIdBO) {
        String accessToken = deviceService.getAccessToken(selectDeviceByIdBO.getDeviceId());
        Device device = deviceService.selectDeviceById(selectDeviceByIdBO.getDeviceId());
        Map<String, Object> result = new HashMap<>();
        result.put("url", device.getVideoUrl());
        result.put("accessToken", accessToken);
        return JSONResult.ok(result);
    }

    /**
     * 升级设备固件
     */
    @PostMapping("/updateDeviceFirmware")
    @PreFuncAuth("SYS:DEVICE:OTA")
    public JSONResult updateDeviceFirmware(@Valid @RequestBody SelectDeviceByIdBO selectDeviceByIdBO){
        Long deviceId = selectDeviceByIdBO.getDeviceId();
        String topicName = deviceId + "/"+ TopicConstants.OTA_TOPIC;
        JSONObject jsonObject = new JSONObject();
        String version = deviceService.selectLatestFirmwareVersion(deviceId);
        String firmwareUrl = deviceService.selectLatestFirmwareUrl(deviceId);
        jsonObject.set("version", version);
        jsonObject.set("firmwareUrl",firmwareUrl);
        MqttUtil.sendToMqtt(topicName, JSONUtil.toJsonStr(jsonObject));
        return JSONResult.ok();
    }

    /**
     * 固件下载
     */
    @GetMapping("/firmware/{path}/**")
    public ResponseEntity<InputStreamResource> getFirmwareUpdateUrl(@PathVariable String path, HttpServletRequest request) throws Exception {
        final String pathq = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
        final String bestMatchingPattern = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString();
        String arguments = new AntPathMatcher().extractPathWithinPattern(bestMatchingPattern, pathq);
        String filename;
        if (StringUtils.isNotBlank(arguments)) {
            filename = '/' + path + '/' + arguments;
        } else {
            filename = path;
        }
        InputStream inputStream = minioUtil.getFileInputStream(filename);
        InputStreamResource resource = new InputStreamResource(inputStream);

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=firmware.bin")
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .contentLength(minioUtil.getSize(filename))
                .body(resource);
    }
}
